package org.example.search.service.impl;

import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.example.search.dto.PageResponse;
import org.example.search.entity.Order;
import org.example.search.repository.OrderRepository;
import org.example.search.service.OrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.Criteria;
import org.springframework.data.elasticsearch.core.query.CriteriaQuery;
import org.springframework.data.elasticsearch.core.query.HighlightQuery;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;

@Slf4j
@Service
public class OrderServiceImpl implements OrderService {
    @Autowired
    private OrderRepository orderRepository;
    @Autowired
    private ElasticsearchRestTemplate elasticsearchRestTemplate;

    @Override
    public void saveAll(List<Order> orders) {
        orderRepository.saveAll(orders);
    }

    @Override
    public Order findById(Integer id) {
        return orderRepository.findById(id).orElse(null);
    }

    @Override
    public void deleteById(Integer id) {
        orderRepository.deleteById(id);

    }

    @Override
    public void updateById(Order order) {
        orderRepository.save(order);
    }

    @Override
    public PageResponse<Order> findList(Order order, Integer pageIndex, Integer pageSize) {
        CriteriaQuery criteriaQuery = new CriteriaQuery(
                new Criteria()
                        .and(new Criteria("orderDesc").contains(order.getOrderDesc()))
                        .and(new Criteria("orderNo").is(order.getOrderNo())))
                .setPageable(PageRequest.of(pageIndex, pageSize));
        SearchHits<Order> hits = elasticsearchRestTemplate.search(criteriaQuery, Order.class);
        List<Order> orderList = hits.get().map(SearchHit::getContent).collect(Collectors.toList());
        PageResponse<Order> response = new PageResponse<>();
        response.setTotal(hits.getTotalHits());
        response.setResult(orderList);
        return response;
    }

    @Override
    public PageResponse<Order> findAll(Integer pageIndex, Integer pageSize) {
        Page<Order> page = orderRepository.findAll(PageRequest.of(pageIndex, pageSize));
        PageResponse<Order> response = new PageResponse<>();
        response.setTotal(page.getTotalElements());
        response.setResult(page.getContent());
        return response;
    }

    @Override
    public PageResponse<Order> findHighlight(Order order, Integer pageIndex, Integer pageSize) {
        PageResponse<Order> pageResponse = new PageResponse<>();
        if (order == null) {
            pageResponse.setTotal(0L);
            pageResponse.setResult(new ArrayList<>());
            return pageResponse;
        }
        CriteriaQuery criteriaQuery = new CriteriaQuery(
                new Criteria()
                        .and(new Criteria("orderDesc").contains(order.getOrderDesc()))
                        .and(new Criteria("orderNo").is(order.getOrderNo())))
                .setPageable(PageRequest.of(pageIndex, pageSize));
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.field("orderNo").field("orderDesc");
        highlightBuilder.requireFieldMatch(false);
        highlightBuilder.preTags("<h3 style=\"color:blue\">");
        highlightBuilder.postTags("</h3>");

        HighlightQuery highlightQuery = new HighlightQuery(highlightBuilder);
        criteriaQuery.setHighlightQuery(highlightQuery);

        SearchHits<Order> searchHits = elasticsearchRestTemplate.search(criteriaQuery, Order.class);
        List<Order> result = searchHits.get().map(new Function<SearchHit<Order>, Order>() {
            @Override
            public Order apply(SearchHit<Order> orderSearchHit) {
                Order element = orderSearchHit.getContent();
                element.setHighlights(orderSearchHit.getHighlightFields());
                return element;
            }
        }).collect(Collectors.toList());
        pageResponse.setTotal(searchHits.getTotalHits());
        pageResponse.setResult(result);
        return pageResponse;
    }
}
